<!doctype html>
<html>

<head>
  <meta charset="utf-8" />
  <title>API Proxy 规则管理</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <!-- <link type="text/css" rel="stylesheet" class="__meteor-css__" href="jsoneditor.min.css"> -->
  <style>
    :root {
      --primary-color: #4f46e5;
      --primary-hover: #4338ca;
      --success-color: #10b981;
      --warning-color: #f59e0b;
      --danger-color: #ef4444;
      --bg-primary: #ffffff;
      --bg-secondary: #f8fafc;
      --bg-card: #ffffff;
      --border-color: #e2e8f0;
      --text-primary: #1e293b;
      --text-secondary: #64748b;
      --text-muted: #94a3b8;
      --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
      --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
      --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
      --radius-sm: 4px;
      --radius-md: 8px;
      --radius-lg: 12px;
      color-scheme: light dark;
    }

    @media (prefers-color-scheme: dark) {
      :root {
        --bg-primary: #0f172a;
        --bg-secondary: #1e293b;
        --bg-card: #334155;
        --border-color: #475569;
        --text-primary: #f1f5f9;
        --text-secondary: #cbd5e1;
        --text-muted: #94a3b8;
      }
    }

    * {
      box-sizing: border-box;
    }

    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
      margin: 0;
      background: var(--bg-secondary);
      color: var(--text-primary);
      line-height: 1.6;
    }

    /* Header */
    header {
      display: flex;
      align-items: center;
      gap: 16px;
      padding: 16px 24px;
      background: var(--bg-primary);
      border-bottom: 1px solid var(--border-color);
      position: sticky;
      top: 0;
      z-index: 100;
      box-shadow: var(--shadow-sm);
    }

    h1 {
      font-size: 20px;
      font-weight: 600;
      margin: 0;
      color: var(--text-primary);
    }

    .toolbar {
      display: flex;
      gap: 12px;
      align-items: center;
      margin-left: auto;
      flex-wrap: wrap;
    }

    .toggle {
      display: flex;
      align-items: center;
      gap: 8px;
    }

    /* Main Layout */
    main {
      display: grid;
      grid-template-columns: 1fr 420px;
      gap: 24px;
      padding: 24px;
      max-width: 1600px;
      margin: 0 auto;
    }

    @media (max-width: 1200px) {
      main {
        grid-template-columns: 1fr;
        gap: 16px;
      }
    }

    /* Cards */
    .card {
      background: var(--bg-card);
      border: 1px solid var(--border-color);
      border-radius: var(--radius-lg);
      box-shadow: var(--shadow-md);
      overflow: hidden;
    }

    .card-header {
      padding: 20px 24px 16px;
      border-bottom: 1px solid var(--border-color);
      background: var(--bg-primary);
    }

    .card-title {
      font-size: 16px;
      font-weight: 600;
      margin: 0;
      color: var(--text-primary);
    }

    .card-content {
      padding: 24px;
    }

    /* Form Styles */
    .form-group {
      margin-bottom: 20px;
    }

    .form-row {
      display: flex;
      gap: 16px;
      margin-bottom: 20px;
    }

    .form-row > * {
      flex: 1;
    }

    label {
      display: block;
      font-size: 14px;
      font-weight: 500;
      color: var(--text-primary);
      margin-bottom: 6px;
    }

    input[type="text"],
    input[type="number"],
    select,
    textarea {
      width: 100%;
      padding: 10px 12px;
      border: 1px solid var(--border-color);
      border-radius: var(--radius-md);
      background: var(--bg-primary);
      color: var(--text-primary);
      font-size: 14px;
      transition: all 0.2s ease;
    }

    input:focus,
    select:focus,
    textarea:focus {
      outline: none;
      border-color: var(--primary-color);
      box-shadow: 0 0 0 3px rgb(79 70 229 / 0.1);
    }

    textarea {
      font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
      min-height: 80px;
      resize: vertical;
    }

    /* Buttons */
    .btn {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      padding: 8px 16px;
      border: 1px solid var(--border-color);
      border-radius: var(--radius-md);
      background: var(--bg-primary);
      color: var(--text-primary);
      font-size: 14px;
      font-weight: 500;
      cursor: pointer;
      transition: all 0.2s ease;
      text-decoration: none;
    }

    .btn:hover {
      background: var(--bg-secondary);
      transform: translateY(-1px);
      box-shadow: var(--shadow-sm);
    }

    .btn-primary {
      background: var(--primary-color);
      color: white;
      border-color: var(--primary-color);
    }

    .btn-primary:hover {
      background: var(--primary-hover);
      border-color: var(--primary-hover);
    }

    .btn-success {
      background: var(--success-color);
      color: white;
      border-color: var(--success-color);
    }

    .btn-warning {
      background: var(--warning-color);
      color: white;
      border-color: var(--warning-color);
    }

    .btn-danger {
      background: var(--danger-color);
      color: white;
      border-color: var(--danger-color);
    }

    .btn-sm {
      padding: 4px 8px;
      font-size: 12px;
    }

    /* Collapsible Sections */
    .collapsible {
      border: 1px solid var(--border-color);
      border-radius: var(--radius-md);
      margin-bottom: 16px;
      overflow: hidden;
    }

    .collapsible-header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 12px 16px;
      background: var(--bg-secondary);
      cursor: pointer;
      user-select: none;
      transition: background-color 0.2s ease;
    }

    .collapsible-header:hover {
      background: var(--border-color);
    }

    .collapsible-title {
      display: flex;
      align-items: center;
      gap: 8px;
      font-weight: 500;
      color: var(--text-primary);
    }

    .collapsible-icon {
      transition: transform 0.2s ease;
    }

    .collapsible.expanded .collapsible-icon {
      transform: rotate(90deg);
    }

    .collapsible-content {
      padding: 0 16px;
      max-height: 0;
      overflow: hidden;
      transition: all 0.3s ease;
    }

    .collapsible.expanded .collapsible-content {
      padding: 16px;
      max-height: 1000px;
    }

    /* Table Styles */
    .table-container {
      overflow-x: auto;
    }

    table {
      width: 100%;
      border-collapse: collapse;
      font-size: 13px;
    }

    th {
      background: var(--bg-secondary);
      color: var(--text-primary);
      font-weight: 600;
      padding: 12px 8px;
      text-align: left;
      border-bottom: 2px solid var(--border-color);
    }

    td {
      padding: 12px 8px;
      border-bottom: 1px solid var(--border-color);
      vertical-align: middle;
    }

    tr:hover {
      background: var(--bg-secondary);
    }

    /* Rule Status */
    .rule-status {
      display: inline-flex;
      align-items: center;
      gap: 4px;
      padding: 2px 8px;
      border-radius: 12px;
      font-size: 11px;
      font-weight: 500;
    }

    .rule-status.enabled {
      background: rgb(16 185 129 / 0.1);
      color: var(--success-color);
    }

    .rule-status.disabled {
      background: rgb(148 163 184 / 0.1);
      color: var(--text-muted);
    }

    /* Drag Handle */
    .drag-handle {
      cursor: grab;
      color: var(--text-muted);
      padding: 4px;
      font-size: 14px;
      user-select: none;
      transition: color 0.2s ease;
    }

    .drag-handle:hover {
      color: var(--primary-color);
    }

    .drag-handle:active {
      cursor: grabbing;
    }

    .sortable-ghost {
      opacity: 0.5;
      background: var(--bg-secondary);
    }

    .sortable-placeholder {
      background: rgba(79, 70, 229, 0.1) !important;
      border: 2px dashed rgba(79, 70, 229, 0.3) !important;
    }

    /* Table row hover effects */
    tbody tr {
      transition: all 0.2s ease;
    }

    tbody tr:hover {
      background: var(--bg-secondary);
      transform: translateY(-1px);
      box-shadow: var(--shadow-sm);
    }

    tbody tr[draggable="true"] {
      cursor: move;
    }

    /* Form validation styles */
    .form-error {
      border-color: var(--danger-color) !important;
      box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1) !important;
    }

    .form-success {
      border-color: var(--success-color) !important;
      box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1) !important;
    }

    /* Loading states */
    .btn.loading {
      opacity: 0.7;
      pointer-events: none;
    }

    .btn.loading::after {
      content: "...";
      animation: loading 1s infinite;
    }

    @keyframes loading {
      0%, 33% { content: "..."; }
      34%, 66% { content: "...."; }
      67%, 100% { content: "....."; }
    }

    /* Toast notifications */
    .toast {
      position: fixed;
      top: 20px;
      right: 20px;
      background: var(--bg-card);
      border: 1px solid var(--border-color);
      border-radius: var(--radius-md);
      padding: 12px 16px;
      box-shadow: var(--shadow-lg);
      z-index: 1001;
      transform: translateX(400px);
      transition: transform 0.3s ease;
    }

    .toast.show {
      transform: translateX(0);
    }

    .toast.success {
      border-left: 4px solid var(--success-color);
    }

    .toast.error {
      border-left: 4px solid var(--danger-color);
    }

    .toast.warning {
      border-left: 4px solid var(--warning-color);
    }

    /* Utilities */
    .nowrap {
      white-space: nowrap;
    }

    .text-muted {
      color: var(--text-muted);
    }

    .text-sm {
      font-size: 12px;
    }

    .mb-4 {
      margin-bottom: 16px;
    }

    .flex {
      display: flex;
    }

    .items-center {
      align-items: center;
    }

    .justify-between {
      justify-content: space-between;
    }

    .gap-2 {
      gap: 8px;
    }

    .gap-4 {
      gap: 16px;
    }

    /* Icons */
    .icon {
      width: 16px;
      height: 16px;
      display: inline-block;
    }

    /* Responsive */
    @media (max-width: 768px) {
      .toolbar {
        flex-direction: column;
        align-items: stretch;
        gap: 8px;
      }

      .form-row {
        flex-direction: column;
      }

      main {
        padding: 16px;
      }
    }
  </style>
</head>

<body id="options">
  <header>
    <h1>🔧 API Proxy 规则管理</h1>
    <div class="toolbar">
      <input id="searchInput" type="text" placeholder="🔍 搜索规则..." style="width:240px;">
      <select id="groupFilter" style="width:160px;">
        <option value="">📁 全部分组</option>
      </select>
      <button id="addRuleBtn" class="btn btn-primary">➕ 新增规则</button>
      <button id="importBtn" class="btn">📥 导入</button>
      <button id="exportBtn" class="btn">📤 导出</button>
      <input type="file" id="importFile" accept=".json,application/json" style="display:none" />
    </div>
    <div class="toggle">
      <input id="enabledSwitch" type="checkbox" />
      <label for="enabledSwitch">🔄 全局启用</label>
    </div>
  </header>

  <main style="height: calc(100vh - 75px);">
    <!-- <div id="editor_holder"></div> -->
    <section class="card" style="height: 100%; overflow:auto">
      <div class="card-header">
        <h2 class="card-title">📋 规则列表</h2>
      </div>
      <div class="card-content">
        <div class="text-sm text-muted mb-4" id="summary"></div>
        <div class="table-container">
          <table>
            <thead>
              <tr>
                <th style="width: 30px;"></th>
                <th style="width: 60px;">状态</th>
                <th>名称</th>
                <!-- <th>分组</th> -->
                <th>匹配规则</th>
                <th>动作类型</th>
                <th style="width: 200px;">操作</th>
              </tr>
            </thead>
            <tbody id="rulesTbody"></tbody>
          </table>
        </div>
      </div>
    </section>

    <aside class="card" style="height: 100%; overflow:auto">
      <div class="card-header">
        <h2 class="card-title">✏️ 规则编辑</h2>
      </div>
      <div class="card-content">
        <form id="ruleForm">
          <input type="hidden" id="ruleId" />
          
          <!-- 基本信息 -->
          <div class="collapsible expanded">
            <div class="collapsible-header">
              <div class="collapsible-title">
                <span class="collapsible-icon">▶</span>
                📝 基本信息
              </div>
            </div>
            <div class="collapsible-content">
              <div class="form-row">
                <div>
                  <label>规则名称</label>
                  <input type="text" id="ruleName" placeholder="例：替换生产API为测试环境" />
                </div>
                <div>
                  <label>分组标签</label>
                  <input type="text" id="ruleGroup" placeholder="例：开发环境" />
                </div>
              </div>
            </div>
          </div>

          <!-- 匹配条件 -->
          <div class="collapsible expanded">
            <div class="collapsible-header">
              <div class="collapsible-title">
                <span class="collapsible-icon">▶</span>
                🎯 匹配条件
              </div>
            </div>
            <div class="collapsible-content">
              <div class="form-row">
                <div>
                  <label>匹配类型</label>
                  <select id="matchType">
                    <option value="string">🔤 字符串包含</option>
                    <option value="regex">🔍 正则表达式</option>
                  </select>
                </div>
                <div>
                  <label>URL 匹配规则</label>
                  <input type="text" id="matchValue" placeholder="例：/api/user 或 ^https?://api\.example\.com" />
                </div>
              </div>
              <div class="form-group">
                <label>HTTP 方法 (可选，逗号分隔)</label>
                <input type="text" id="matchMethods" placeholder="例：GET,POST,PUT" />
              </div>
            </div>
          </div>

          <!-- 动作类型 -->
          <div class="form-group">
            <label>🎬 动作类型</label>
            <select id="actionType">
              <option value="modifyRequest">🔄 修改请求</option>
              <option value="modifyResponse">📝 修改响应</option>
              <option value="mockResponse">🎭 Mock 响应</option>
            </select>
          </div>

          <!-- 请求改写 -->
          <div class="collapsible" id="requestSection">
            <div class="collapsible-header">
              <div class="collapsible-title">
                <span class="collapsible-icon">▶</span>
                📤 请求改写
              </div>
            </div>
            <div class="collapsible-content">
              <div class="form-row">
                <div>
                  <label>URL 替换 - 查找</label>
                  <input type="text" id="reqUrlFrom" placeholder="例：https://prod.api.com" />
                </div>
                <div>
                  <label>URL 替换 - 替换为</label>
                  <input type="text" id="reqUrlTo" placeholder="例：https://test.api.com" />
                </div>
              </div>
              <div class="form-group">
                <label>
                  <input type="checkbox" id="reqUrlIsRegex" />
                  使用正则表达式替换
                </label>
              </div>
              <div class="form-row">
                <div>
                  <label>请求头设置 (JSON 格式)</label>
                  <textarea id="reqHeadersSet" placeholder='{"Authorization": "Bearer token", "X-Custom": "value"}'></textarea>
                </div>
                <div>
                  <label>移除请求头 (逗号分隔)</label>
                  <input type="text" id="reqHeadersRemove" placeholder="authorization, cookie, x-token" />
                </div>
              </div>
              <div class="form-group">
                <label>请求体替换</label>
                <div class="form-row">
                  <select id="reqBodyMode" style="flex: 0 0 120px;">
                    <option value="regexReplace">正则替换</option>
                    <option value="replace">直接替换</option>
                  </select>
                  <input type="text" id="reqBodyFind" placeholder="查找内容" />
                  <input type="text" id="reqBodyReplace" placeholder="替换为" />
                </div>
              </div>
            </div>
          </div>

          <!-- 响应改写 -->
          <div class="collapsible" id="responseSection">
            <div class="collapsible-header">
              <div class="collapsible-title">
                <span class="collapsible-icon">▶</span>
                📥 响应改写 / Mock
              </div>
            </div>
            <div class="collapsible-content">
              <div class="form-row">
                <div>
                  <label>响应头设置 (JSON 格式)</label>
                  <textarea id="respHeadersSet" placeholder='{"Cache-Control": "no-cache", "X-Custom": "value"}'></textarea>
                </div>
                <div>
                  <label>移除响应头 (逗号分隔)</label>
                  <input type="text" id="respHeadersRemove" placeholder="content-length, server" />
                </div>
              </div>
              <div class="form-group">
                <label>响应体处理</label>
                <div class="form-row">
                  <select id="respBodyMode" style="flex: 0 0 120px;">
                    <option value="regexReplace">正则替换</option>
                    <option value="replace">直接替换</option>
                  </select>
                  <input type="text" id="respBodyFind" placeholder="查找内容" />
                </div>
                <textarea id="respBodyReplace" placeholder="替换为的内容 (Mock 模式下为完整响应体)" style="margin-top: 8px;"></textarea>
              </div>
              <div class="form-row">
                <div>
                  <label>Mock 状态码</label>
                  <input type="number" id="mockStatus" placeholder="200" min="100" max="599" />
                </div>
                <div>
                  <label class="text-muted text-sm">💡 Mock 模式将直接返回设置的响应头和响应体</label>
                </div>
              </div>
            </div>
          </div>

          <!-- 操作按钮 -->
          <div class="flex justify-between" style="margin-top: 24px;">
            <button type="button" id="previewConfig" class="btn">👁️ 预览配置</button>
            <div class="flex gap-2">
              <button type="button" id="resetForm" class="btn">🗑️ 清空</button>
              <button type="submit" id="saveRuleBtn" class="btn btn-primary">💾 保存规则</button>
            </div>
          </div>
        </form>
      </div>
    </aside>
  </main>

  <!-- 预览模态框 -->
  <div id="previewModal" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000;">
    <div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: var(--bg-card); border-radius: var(--radius-lg); padding: 24px; max-width: 600px; width: 90%; max-height: 80%; overflow-y: auto;">
      <div class="flex justify-between items-center mb-4">
        <h3>📋 规则配置预览</h3>
        <button id="closePreview" class="btn btn-sm">✕</button>
      </div>
      <pre id="previewContent" style="background: var(--bg-secondary); padding: 16px; border-radius: var(--radius-md); overflow-x: auto; font-size: 12px;"></pre>
    </div>
  </div>

  <script src="jquery-3.7.1.slim.min.js"></script>
  <script src="sortable-simple.js"></script>
  <!-- <script src="jsoneditor.min.js"></script> -->
  <script src="options-app.js"></script>
</body>

</html>
